#include <stdio.h>
#include <stdlib.h>
#include "sj_print.h"

#include "task_manager.h"
#include "os.h"


//#define sj_kprintf

static sj_void task_loop_entry_func(sj_void *arg)
{
    //sj_kprintf("enter task_loop_entry_func\r\n");
    struct sj_task_t *handle =(struct sj_task_t*)arg;
    struct sj_task_data *task_data = handle->task_data;
    OS_ERR err;
    if(handle->name!=NULL)
    {
        //sj_kprintf("handle->name %s \r\n",handle->name);
    }   
    if(handle->init_func!=NULL)
    {
        handle->init_func();
    }
    while(!task_data->exit)
	{
        int timeout = task_data->periodtime;
        if(timeout>0)
        {
            task_data->status=TASK_STATUS_BLOCK;
            OSSemPend(&task_data->sem,timeout,OS_OPT_PEND_BLOCKING,0,&err);
        }
        else if(timeout<0)
        {
            task_data->status=TASK_STATUS_BLOCK;
            OSSemPend(&task_data->sem,0,OS_OPT_PEND_BLOCKING,0,&err);           
        }
        task_data->status=TASK_STATUS_EVENT;
        if(err==OS_ERR_TIMEOUT)
        {
            task_data->status=TASK_STATUS_TIMEOUT;
        }
        if(task_data->exit==1)
        {
            break;
        }       
        if(handle->run_func!=NULL)
        {
            handle->run_func(task_data->private_ptr);
        }
	}
    if(handle->exit_func!=NULL)
    {
        handle->exit_func();
    }
}

sj_int8 sj_task_create(struct sj_task_t *task)
{   
    sj_int8 ret = 0;
    OS_ERR err;
    struct sj_task_data *task_data = task->task_data;

    OSSemCreate(&task_data->sem,task->name,0,&err);
    if(err!=OS_ERR_NONE)
    {
        ret = -1;
        goto out;
    }    
    OSTaskCreate((OS_TCB*)&task_data->tcb,\
                 task->name,\
                 task_loop_entry_func,\
                 task,\
                 task_data->prio,\
                 (CPU_STK*)task_data->stk_base,\
                 (CPU_STK_SIZE)task_data->stk_size/10,\
                 (CPU_STK_SIZE)task_data->stk_size,\
                 (OS_MSG_QTY)0,\
                 (OS_TICK)0,\
                 0,\
                 (OS_OPT)OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,\
                 (OS_ERR*)&err);
    if(err!=OS_ERR_NONE)
    {
        ret = -1;
        goto out;
    }
    task_data->inited =1;
    task_data->exit =0;
    task_data->status=0;
out:
	return ret;
}

sj_int8 sj_task_destory(struct sj_task_t *task)
{
	sj_int8 ret = 0;
    OS_ERR err;
    struct sj_task_data *task_data = task->task_data;
    if(task==NULL)
    {
    	ret = -1;
        goto out;
    }
    if(task_data->inited==0)
    {
        goto out;
    }

    task_data->exit=1;

    task_data->inited=0;

    if(task_data->status>TASK_STATUS_RUNNING)
    {
        OSSemPost(&task_data->sem,OS_OPT_POST_1,&err);
    }

    OSTaskDel((OS_TCB*)&task_data->tcb,&err);

    OSSemDel(&task_data->sem,OS_OPT_POST_1,&err);

out:
	return ret;	
}


sj_int8 sj_task_run_onetime(struct sj_task_t *task)
{
	sj_int8 ret = 0;
    OS_ERR err;
    struct sj_task_data *task_data = task->task_data;
    if(task==NULL)
    {
        return -1;
    }
    if(task_data->inited==0)
    {
        return -1;
    }
    if(task_data->status>TASK_STATUS_RUNNING)
    {
        OSSemPost(&task_data->sem,OS_OPT_POST_1,&err);
    }

	return ret;
}

sj_int8 sj_task_resume(struct sj_task_t *task,sj_int32 periodtime)
{
	sj_int8 ret = 0;
    OS_ERR err;
    struct sj_task_data *task_data = task->task_data;
    if(task==NULL)
    {
    	ret = -1;
        goto out;
    }

    if(task_data->inited==0)
    {
    	ret = -2;
        goto out;
    }

    task_data->periodtime=periodtime;
    
    if(task_data->status>TASK_STATUS_SUSPEDN)
    {
        OSTaskResume((OS_TCB*)&task_data->tcb,&err);
    }
    else if(task_data->status>TASK_STATUS_RUNNING)
    {
        OSSemPost(&task_data->sem,OS_OPT_POST_1,&err);
    }
out:
	return ret;
}

sj_int8 sj_task_suspend(struct sj_task_t *task)
{
	sj_int8 ret = 0;
    OS_ERR err;
    struct sj_task_data *task_data = task->task_data;
    if(task==NULL)
    {
    	ret = -1;
        goto out;
    }

    if(task_data->inited==0)
    {
    	ret = -2;
        goto out;
    }
    task_data->periodtime=-1;
    OSTaskSuspend((OS_TCB*)&task_data->tcb,&err);
    if(err!=OS_ERR_NONE)
    {
        ret = -3;
        goto out;
    }
    task_data->status =TASK_STATUS_SUSPEDN;
out:
	return ret;
}

sj_int8 sj_task_get_current_state(struct sj_task_t *task)
{
    return task->task_data->status;
}


sj_int8 sj_sem_create(sj_sem *sem,sj_int8 v)
{
    OS_ERR err;
    OSSemCreate(sem,NULL,0,&err);

    if(err!=OS_ERR_NONE)
    {
        return -1;
    }
    return 0;
}

sj_int8 sj_sem_destory(sj_sem* sem)
{
    OS_ERR err;
    OSSemDel(sem,OS_OPT_POST_1,&err);
    if(err!=OS_ERR_NONE)
    {
        return -1;
    }
    return 0;
}

sj_int8 sj_sem_wait(sj_sem* sem,sj_int32 timeout)
{
    OS_ERR err;   
    OSSemPend(sem,timeout,OS_OPT_PEND_BLOCKING,0,&err);
    if(err==OS_ERR_TIMEOUT)
    {
        return 0;
    }
    if(err!=OS_ERR_NONE)
    {
        return -1;
    }
    return 1;
}

sj_int8 sj_sem_post(sj_sem* sem)
{
    OS_ERR err;
    OSSemPost(sem,OS_OPT_POST_1,&err);
    if(err!=OS_ERR_NONE)
    {
        return -1;
    }
    return 0;
}

